using System;
using System.Collections.Generic;
using System.Linq;
using Irony.Ast;
using Irony.Parsing;

namespace Flit
{

    /// <summary>
    /// Represents a state within the fluent interface. Each state can have a number of methods (transitions) that exit the state.
    /// </summary>
    public class State : GraphItem, IAstNodeInit
    {
        /// <summary>
        /// Instantiate a new state. Do not call this directly, let the parser build these
        /// </summary>
        public State()
        {
            GenericAttributes = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        }

        /// <summary>
        /// Called by Irony
        /// </summary>
        /// <param name="context"></param>
        /// <param name="parseNode"></param>
        public void Init(ParsingContext context, ParseTreeNode parseNode)
        {
            Identifier = parseNode.ChildNodes[0].Token.ValueString;
            Label = parseNode.Descendants().Select(x => x.AstNode).OfType<Label>().SingleOrDefault()??new Label {Name = Identifier};

            var v = parseNode.DescendantsWithTermType(x => x.GenericAttribute);
            foreach (var n in v)
            {
                GenericAttributes[n.ChildNodes[0].Token.ValueString] = n.ChildNodes[1].Token.ValueString;
            }
        }

        /// <summary>
        /// The unique identifier of this state
        /// </summary>
        public string Identifier { get; internal set; }

        /// <summary>
        /// The label attribute (or it's inferred value) of this state: x[<b>label="foo(int bar)"</b>, color=red]
        /// </summary>
        public Label Label { get; internal set; }

        /// <summary>
        /// All non-label attributes of this state: x[label="foo(int bar), <b>color=red"</b>]
        /// </summary>
        public Dictionary<string, string> GenericAttributes { get; private set; }

        /// <summary>
        /// Whether or not this state was really declared in the Flit DSL. If the state is implicit, that means it was inferred by being used in a transition
        /// </summary>
        public bool IsImplicit { get; set; }

        /// <summary>
        /// All the transitions leaving this state
        /// </summary>
        public IEnumerable<Transition> OutgoingTransitions
        {
            get
            {
                return Graph.EdgesFrom(this);
            }
        }
    }
}